﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using SharePhone.Common;
using SharePhone.Common.List;
using SharePhone.Common.Web;
using SharePhone.Core;
using SharePhone.Provider.WebServices;
using SharePhone.Utility;

namespace SharePhone.Provider
{
    public delegate void ListTransferCompleted<T>(SPList<T> list) where T : BaseItem, new();

    public delegate void ListsTransferCompleted(List<SPList<BaseItem>> lists);

    public class ListProvider
    {
        public static void GetList<T>(string name, string spUrl, ListTransferCompleted<T> callback,
                                      CredentialSettings credentials) where T : BaseItem, new()
        {
            if (String.IsNullOrEmpty(spUrl))
                throw new NullReferenceException(
                    "No web url has been configured for this context, please set the WebUrl property");
            //ListsSoapClient client = ServiceFactory.GetListService(spUrl, credentials);
            var listService = new SPListService(spUrl, credentials);
            listService.GetListCompleted += (object sender, RequestCompleteEventArgs e) =>
                                                {
                                                    SPList<T> list = ParseListXML<T>(e.Result);
                                                    list.LastRefreshTimeStamp = DateTime.Now;
                                                    callback(list);
                                                };
            listService.GetListAsync<T>(name);
            //client.GetListCompleted += (object sender, GetListCompletedEventArgs e) => {
            //    SPList<T> list = ParseListXML<T>(e.Result);
            //    list.LastRefreshTimeStamp = DateTime.Now;
            //    callback(list);
            //};
            //client.GetListAsync(name);
        }

        public static void GetListCollection(SPWeb web, ListsTransferCompleted callback, CredentialSettings credentials)
        {
            var client = new SPListService(web.Url, credentials);
            client.GetListCollectionCompleted += (object sender, RequestCompleteEventArgs e) =>
                                                     {
                                                         List<SPList<BaseItem>> lists = ParseListCollectionXml(
                                                             e.Result, web);
                                                         callback(lists);
                                                     };
            client.GetListCollectionAsync();
        }

        public static void UpdateList<T>(SPList<T> list, string spUrl, CredentialSettings credentials)
            where T : BaseItem, new()
        {
            //using (ListsSoapClient client = ServiceFactory.GetListService(spUrl, credentials)) {
            //    client.UpdateList(list.Title, null, null, null, null, null); //TODO: fix this
            //}
        }

        #region Internal parsers

        internal static SPList<T> ParseListXML<T>(XElement list) where T : BaseItem, new()
        {
            XNamespace s = "http://schemas.microsoft.com/sharepoint/soap/";
            var spList = new SPList<T>();
            spList.Title = XmlUtility.GetAttributeValue(list, "Title");
            int itemCount;
            if (Int32.TryParse(XmlUtility.GetAttributeValue(list, "ItemCount"), out itemCount))
            {
                spList.ItemCount = itemCount;
            }
            spList.Modified = XmlUtility.GetAttributeValue(list, "Modified");
            spList.Created = XmlUtility.GetAttributeValue(list, "Created");
            spList.Name = XmlUtility.GetAttributeValue(list, "Name");
            spList.EnableAttachments = Boolean.Parse(XmlUtility.GetAttributeValue(list, "EnableAttachments"));
            spList.EnableVersioning = Boolean.Parse(XmlUtility.GetAttributeValue(list, "EnableVersioning"));
            spList.EnableModeration = Boolean.Parse(XmlUtility.GetAttributeValue(list, "EnableModeration"));
            spList.EnableMinorVersion = Boolean.Parse(XmlUtility.GetAttributeValue(list, "EnableMinorVersion"));
            spList.BaseType = Int32.Parse(XmlUtility.GetAttributeValue(list, "BaseType"));
            spList.RegionalSettings = ParseRegionalSettingsXml(list.Element(s + "RegionalSettings"));
            spList.Fields = new List<FieldInfo>();
            IEnumerable<XElement> fieldInfoList = list.Descendants(s + "Field");
            foreach (var field in fieldInfoList)
            {
                if (field.Attribute("ID") != null)
                {
                    var fi = new FieldInfo();
                    fi.Properties = GetFieldProperties(field);
                    spList.Fields.Add(fi);
                }
            }
            return spList;
        }

        private static List<FieldProperty> GetFieldProperties(XElement field)
        {
            return field.Attributes().Select(attribute => new FieldProperty {Name = attribute.Name.LocalName, Value = attribute.Value}).ToList();
        }

        internal static List<SPList<BaseItem>> ParseListCollectionXml(XElement xml, SPWeb parentWeb)
        {
            var listCollection = new List<SPList<BaseItem>>();
            IEnumerable<XElement> lists = xml.Elements();
            foreach (SPList<BaseItem> spList in lists.Select(ParseListXML<BaseItem>))
            {
                spList.ParentWeb = parentWeb;
                listCollection.Add(spList);
            }
            return listCollection;
        }

        internal static RegionalSettings ParseRegionalSettingsXml(XElement settings)
        {
            if (settings == null)
                return null;
            XNamespace s = "http://schemas.microsoft.com/sharepoint/soap/";
            var rs = new RegionalSettings
                         {
                             Language = Int32.Parse(settings.Element(s + "Language").Value),
                             Locale = Int32.Parse(settings.Element(s + "Locale").Value),
                             CalendarType = Int32.Parse(settings.Element(s + "CalendarType").Value),
                             Time24 = Boolean.Parse(settings.Element(s + "Time24").Value),
                             TimeZone = settings.Element(s + "TimeZone").Value,
                             SortOrder = settings.Element(s + "SortOrder").Value,
                             Presence = Boolean.Parse(settings.Element(s + "Presence").Value)
                         };
            return rs;
        }

        #endregion
    }
}